package com.easychat.websocket.netty;

import com.easychat.entity.config.AppConfig;
import com.easychat.entity.constants.RedisConstants;
import com.easychat.redis.RedisCache;
import com.easychat.redis.RedisComponent;
import com.easychat.utils.StringTools;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpServerCodec;
import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import io.netty.handler.timeout.IdleStateHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;

import javax.annotation.PreDestroy;
import javax.annotation.Resource;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.util.HashMap;
import java.util.Set;
import java.util.concurrent.TimeUnit;

/**
 * @Author Dongdong
 * @注释
 */
@Component
public class NettyWebSocketStarter {
    // 处理连接的线程组
    private static EventLoopGroup bossGroup = new NioEventLoopGroup();
    // 处理读写的线程组
    private static EventLoopGroup workerGroup = new NioEventLoopGroup();
    private static final Logger logger = LoggerFactory.getLogger(NettyWebSocketStarter.class);

    @Resource
    private RedisCache redisCache;


    //注入自定义的handler
    @Resource
    private HandlerWebSocket handlerWebSocket;
    @Resource
    private AppConfig appConfig;


    //异步 启动netty
    @Async
    public void startNetty() {
        try {
            ServerBootstrap serverBootstrap = new ServerBootstrap();
            serverBootstrap.group(bossGroup, workerGroup)
                    .channel(NioServerSocketChannel.class)
                    .handler(new LoggingHandler(LogLevel.DEBUG))//日志
                    .childHandler(new ChannelInitializer() {
                        @Override
                        protected void initChannel(Channel channel) throws Exception {
                            // 获取管道
                            ChannelPipeline pipeline = channel.pipeline();
                            // 添加http编解码器，支持http协议
                            pipeline.addLast(new HttpServerCodec());
                            // 添加聚合器解码，保证http请求的完整性
                            pipeline.addLast(new HttpObjectAggregator(64 * 1024));
                            //添加心跳  （读超时时间:多长时间未接收到消息，写超时时间，所有类型超时时间）
                            pipeline.addLast(new IdleStateHandler(60, 0, 0, TimeUnit.SECONDS));
                            //添加超时处理器（自己实现）
                            pipeline.addLast(new HandlerHeartBeat());
                            //将http协议升级为ws协议，支持websocket
                            pipeline.addLast(new WebSocketServerProtocolHandler("/ws", null, true, 64 * 1024, true, true, 1000000L));
                            //添加自定义的handler
                            pipeline.addLast(handlerWebSocket);
                        }
                    });
            //多个ws端口
            Integer wsPort = appConfig.getWsPort();
            String wsPortSys = System.getProperty("ws.port");//系统配置参数的端口 优先级更高
            if (!StringTools.isEmpty(wsPortSys)) {
                wsPort = Integer.valueOf(wsPortSys);
            }
            ChannelFuture channelFuture = serverBootstrap.bind(wsPort);
            channelFuture.sync();
            logger.info("netty websocket 服务启动成功，端口：{}", wsPort);
            channelFuture.channel().closeFuture().sync();
//             Integer minConnectionWSPort = (Integer) redisCache.getFirstElement(RedisConstants.REDIS_KEY_WS_PORTS);//获取zset第一个元素
//            Integer connectionCount = redisCache.getScore(RedisConstants.REDIS_KEY_WS_PORTS, minConnectionWSPort);//获取第一个元素的连接数
//            redisCache.add(RedisConstants.REDIS_KEY_WS_PORTS, minConnectionWSPort, connectionCount + 1);//增加连接数
//            // key：   field ：userid    value：ip+port
//            HashMap<String , Integer> map = new HashMap<>();
//            map.put("127.0.0.1", minConnectionWSPort);
//            redisCache.setCacheMap("userConnectionInfo",map);


        } catch (Exception e) {
            logger.error("启动netty websocket失败", e);
        } finally {
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
    }

    /**
     * 关闭netty
     */
    @PreDestroy
    public void close() {
        bossGroup.shutdownGracefully();
        workerGroup.shutdownGracefully();
    }

}
